Flutter AndroidViewController
在 Virtual displays 模式下,在 Flutter 侧,开发者直接打交道的组件是 AndroidView。AndroidView 是一个 StatefulWidget,由于其 State 逻辑较多,于是抽出一个 AndroidViewController 类用于封装嵌入 Android 视图相关的逻辑。在本文中,我们将详细介绍 Virtual displays 模式下 AndroidViewController 的实现原理。搞懂这些后,后续在学 AndroidView 时会轻松很多。
AndroidViewController 功能是控制从 Flutter 侧控制被嵌入的 Android 视图。AndroidViewController 是一个抽象类,Virtual displays 模式下会派生出一个 TextureAndroidViewController 类实现具体逻辑。
需要说明的是,AndroidViewController 这个抽象类不仅用于 Virtual displays 模式,在另外两种模式中(Hybrid composition、Texture Layer Hybrid Composition),都分别使用并实现了这个抽象类。具体可参见《1.1 使用 Flutter webview_flutter 库引入 WebView 能力》一文。
PlatformViewController
PlatformViewController 是 AndroidViewController 的基类,定义了 Flutter 控制原生视图(Platform View)的最基础接口:
abstract class PlatformViewController {
// 每个原生视图都有一个唯一 id,原生侧将此 id 同步到 Flutter 侧
int get viewId;
/// 手势分发分发 PointerEvent 是 Flutter 触摸系统中的事件类
Future<void> dispatchPointerEvent(PointerEvent event);
/// 组件释放销毁生命周期
Future<void> dispose();
/// 清空焦点
Future<void> clearFocus();
}
AndroidViewController 在 PlatformViewController 基础上又扩展出几个核心属性:
// 视图类型
final String _viewType;
// 手势处理
final _AndroidMotionEventConverter _motionEventConverter =
_AndroidMotionEventConverter();
// 文本方向
TextDirection _layoutDirection;
// 引入一个小状态机,有 4 各状态
// waitingForSize
// - creating
// - created
// - disposed
_AndroidViewState _state;
// 这是要传给原生侧的,创建原生视图时的传参
final dynamic _creationParams;
// 传构建参数用的 Channel 通信编码器
final MessageCodec<dynamic>? _creationParamsCodec;
// 原生视图创建完成的通知回调,支持多订阅
final List<PlatformViewCreatedCallback> _platformViewCreatedCallbacks =
<PlatformViewCreatedCallback>[];
// 纹理 ID
int? get textureId;
create 创建原生视图
通过该方法,通知原生侧可以创建原生视图了。具体实现如下:
Future<void> create() async {
// ...
// 这是够抽象方法,需要由子类实现
await _sendCreateMessage();
// 更新状态
_state = _AndroidViewState.created;
// 将“创建好了”这个消息,通知出去
for (final PlatformViewCreatedCallback callback in _platformViewCreatedCallbacks) {
callback(viewId);
}
}
围绕这个方法,有两个核心考虑点:
- 出发时机、条件
- 原生侧收到事件后的响应
TODO:待我后续笔记梳理全面后,将相关章节贴在上面,这样一看便知。
sendMotionEvent 向 Android 分发手势
在 Flutter Virtual displays 模式下,触摸事件分发的链路比较长,并且在 Flutter 与原生之间反复跨越,这也是该模式对手势相关兼容性不佳的原因。
sendMotionEvent 是分发链路中的一环,用于将 Flutter 中的触摸事件转发到这个嵌入的原生视图中。具体实现如下:
Future<void> sendMotionEvent(AndroidMotionEvent event) async {
await SystemChannels.platform_views.invokeMethod<dynamic>(
'touch',
event._asList(viewId),
);
}
可以看到,通过 SystemChannels.platform_views
这个平台视图专门的 Channel,将触摸事件传递到原生侧。
还有一点需要注意,AndroidMotionEvent 是一个 Dart 类,用于表示 Android 侧的手势事件(MotionEvent)。而在 Flutter 中,手势事件是 PointerEvent。
dispatchPointerEvent 接收 Flutter 手势
dispatchPointerEvent 是 sendMotionEvent 的前面一环:Flutter 手势事件先经过 dispatchPointerEvent,将 Flutter 手势事件转换为 Android 事件,然后调用 sendMotionEvent 向 Android 侧发送。具体代码:
@override
Future<void> dispatchPointerEvent(PointerEvent event) async {
// ...
final AndroidMotionEvent? androidEvent =
_motionEventConverter.toAndroidMotionEvent(event);
// ...
if (androidEvent != null) {
await sendMotionEvent(androidEvent);
}
}
clearFocus 消除焦点
直接看代码实现:
/// Clears the focus from the Android View if it is focused.
@override
Future<void> clearFocus() {
if (_state != _AndroidViewState.created) {
return Future<void>.value();
}
return SystemChannels.platform_views.invokeMethod<void>('clearFocus', viewId);
}
可以看到,还是通过 SystemChannels.platform_views
实现的。
Dispose 释放销毁
释放销毁逻辑如下:
@override
Future<void> dispose() async {
// 向原生侧发送销毁通知
if (_state == _AndroidViewState.creating || _state == _AndroidViewState.created)
await _sendDisposeMessage();
// 释放监听回调
_platformViewCreatedCallbacks.clear();
// 更新状态
_state = _AndroidViewState.disposed;
// 可以看到,焦点管理是注册到单例中的
PlatformViewsService._instance._focusCallbacks.remove(viewId);
}
对于焦点管理,在 PlatformViewsService 单例中有一个 _focusCallbacks
,全局管理 PlatformView 的焦点:
/// Maps platform view IDs to focus callbacks.
///
/// The callbacks are invoked when the platform view asks to be focused.
final Map<int, VoidCallback> _focusCallbacks = <int, VoidCallback>{};
PlatformViewCreatedCallback 的订阅者
这个回调用于通知原生视图“创建好了”这个消息,都有哪里关心这个事情呢?
RenderAndroidView
RenderAndroidView 在构造函数中订阅了该消息:
class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
/// Creates a render object for an Android view.
RenderAndroidView({
required AndroidViewController viewController,
required PlatformViewHitTestBehavior hitTestBehavior,
required Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers,
Clip clipBehavior = Clip.hardEdge,
}) : //...
//...
_viewController.addOnPlatformViewCreatedListener(_onPlatformViewCreated);
//...
}
RenderAndroidView 的 _onPlatformViewCreated
做了什么呢?
void _onPlatformViewCreated(int id) {
markNeedsSemanticsUpdate();
}
看起来与 Semantic 即辅助功能相关。
_AndroidViewState
在 _AndroidViewState
(参见《AndroidView》)的 _createNewAndroidView
中也订阅了该消息:
if (widget.onPlatformViewCreated != null) {
_controller
.addOnPlatformViewCreatedListener(widget.onPlatformViewCreated!);
}
它是把 Widget(AndroidView)的 onPlatformViewCreated 回调给注册上了。而 AndroidView 的 onPlatformViewCreated 是提供给开发者的,供开发者关注使用。
本文作者:Maeiee
本文链接:Flutter AndroidViewController
版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!
喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!